#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <vector>

#include "sem.hpp"

template <typename T> class RingQueue {
public:
  RingQueue(int cap)
      : _ring_queue(cap), _cap(cap), _producter_step(0), _consumer_step(0) {
    pthread_mutex_init(&_producter_mtx, nullptr);
    pthread_mutex_init(&_consumer_mtx, nullptr);
  };
  ~RingQueue() {
    pthread_mutex_destroy(&_producter_mtx);
    pthread_mutex_destroy(&_consumer_mtx);
  };

  void Push(T val) {
    _room_sem.P(); // room--
    pthread_mutex_lock(&_producter_mtx);
    _ring_queue[_producter_step++] = val;
    _producter_step %= _cap;
    pthread_mutex_unlock(&_producter_mtx);
    _data_sem.V(); // data++
  };

  T Pop() {
    _data_sem.P();
    pthread_mutex_lock(&_consumer_mtx);
    T out = _ring_queue[_consumer_step++];
    _consumer_step %= _cap;
    pthread_mutex_unlock(&_consumer_mtx);
    _room_sem.V();
  };

private:
  std::vector<T> _ring_queue;
  int _cap;

  int _producter_step;
  int _consumer_step;

  Sem _room_sem;
  Sem _data_sem;

  pthread_mutex_t _producter_mtx;
  pthread_mutex_t _consumer_mtx;
};